#include "../include/WebPageQuery.h"
#include "../include/WebPage.h"
#include <nlohmann/json.hpp>
#include <iostream>
#include <sstream>
#include <cmath>
#include <algorithm>
#include <unistd.h>
using namespace std;
using json = nlohmann::json;



WebPageQuery::WebPageQuery(SplitTool* wordCutTool)
:_wordCutTool(wordCutTool)
{
    makeWebpage();
    readIndex();
}

string WebPageQuery::doQuery(string key)
{
    vector<double> wX = getX(key);
    vector<string> cutRes = _wordCutTool->cut(key);
    set<string> words;
    int cnt = 0;
    for(auto &word : cutRes)
    {   
        words.insert(word);
    }
    vector<set<int>> v_set;
    v_set.resize(words.size());
    
    for(auto &word: words)
    {
        set<pair<int,double>> pageSet = _invertIndexLib[word];
        for(auto it = pageSet.begin(); it != pageSet.end(); ++it)
        {
            v_set[cnt].insert(it->first);
        }
        cnt++;
    }
    set<int> res = v_set[0];
    for(size_t i = 1; i < v_set.size(); i++)
    {
        set<int> tmp;
        set_intersection(v_set[i].begin(),v_set[i].end(),
                         res.begin(),res.end(),
                         inserter(tmp,tmp.begin()));
        res = tmp;
    }
    if(res.size() == 0)
    {
        json js = vector<string>();
        return js.dump();
    }
    else
    {
        vector<string> pageRes;
        int cnt = 0;
        for(int idx : res)
        {
            pageRes.push_back("");
            pageRes[cnt].append(_pages[idx-1]._pageMsg);
            cnt++;
            if(cnt > 10) break;
        }
        json js = pageRes;
        return js.dump();
    }
#if 0
    it++;
    for(;it != words.end(); it++)
    {
        set<pair<int,double>> tmp1 = _invertIndexLib[*it];
        set<pair<int,double>> res;
         set_intersection(
                        pageSet.begin(),pageSet.end(),
                         tmp1.begin(),tmp1.end(),
                         inserter(res,res.begin()));
        pageSet = res;
    }
#endif
}

vector<double> WebPageQuery::getX(string key)
{
    vector<string> cutRes = _wordCutTool->cut(key);
    vector<double> ws;
    int N = cutRes.size();
    unordered_map<string,int> dict;
    for(size_t idx = 0; idx < cutRes.size(); idx++)
    {
        auto it = dict.find(cutRes[idx]);
        if(it != dict.end())
        {
            dict[cutRes[idx]]++;
        }
        else
        {
            dict[cutRes[idx]] = 1;
        }    
    }
    for(auto it = dict.begin(); it != dict.end(); ++it)
    {
        double w = log((N+1)*1.0/(it->second+1)) / log(2);
        //cout << "w = " << w << endl;
        ws.push_back(w);
    }
    return ws;
}

void WebPageQuery::makeWebpage()
{
    ifstream ifs("../data/offsetLib.dat");
    if(!ifs.good())
    {
        cerr << "ifs error in makeWebpage!" << endl;
        ::exit(-1);
    }
    ifstream ifsPage("../data/pageLib.dat");
    if(!ifsPage)
    {
        ifs.close();
        cerr << "ifs error in pagelib.txt";
        return;
    }
    char buf[65535];
    string line;
    int docId;
    int offset, pageSize;
    int cnt = 0;
    while(getline(ifs, line))
    {
        bzero(buf,sizeof(buf));
        stringstream ss(line);
        ss >> docId >> offset >> pageSize;
        ifsPage.read(buf,pageSize);
        string pageMsg(buf);
        _pages.push_back(Webpage(pageMsg));
        cnt++;
    }
}

void WebPageQuery::readIndex()
{
    ifstream ifs("../data/invertIndex.dat");
    if(!ifs)
    {
        cerr << "ifs invertIndex.dat" << endl;
        return;
    }
    string line;
    string key;
    int number;
    double w;
    while(getline(ifs,line))
    {
        istringstream iss(line);
        iss >> key;
        _invertIndexLib[key];
        while(iss >> number >> w)
        {
            _invertIndexLib[key].insert(std::make_pair(number,w));
        }
        //cout <<  "key.size()  "<< _invertIndexLib[key].size() << endl;
    }
}
